<template>
	<Header :titleName="'智能推理知识问答助手'" :titleDesc="'通过多跳推理机制自动分析信息并进行针对性检索，帮助用户获取更全面的信息'"></Header>
	<div class="homeContent">
		<!-- 上传模块 -->
		<div class="uploadModule">
			<div class="iconAndText">
				<el-icon>
					<FolderAdd />
				</el-icon>
				上传知识库
			</div>
			<!-- 文件上传拖拽区 -->
			<div class="uploadArea" @drop="handleDrop">
				<div v-if="files.length === 0" class="uploadAreaText">
					<img src="@/assets/images/upload.png" class="uploadIcont">
					<div class="text">选择或拖拽文件</div>
					<!-- 支持格式 -->
					<div class="supportFormat">(TXT/PDF)</div>
				</div>
				<div v-else>
					<div class="uploadFileList">
						<div v-for="file in files" :key="file.name" class="fileItem">
							<div class="fileName">{{ file.name }}</div>
							<!-- 处理显示文件大小 -->
							<div class="fileSize">{{ formatFileSize(file.size) }}</div>
							<div class="deleteIcon" @click="deleteFile(file)">
								×
							</div>
						</div>
					</div>
				</div>
				<input v-if="fileInputShow" type="file" class="fileInput" @change="handleFileChange" multiple />
			</div>
			<!-- 文件状态 -->
			<div class="fileStatus">
				<div class="text">文件状态</div>
				<div class="status">{{ fileStatus }}</div>
			</div>
		</div>
		<!-- 解析模块 -->
		<div class="parseModule">
			<div class="iconAndText">
				<el-icon>
					<Comment />
				</el-icon>
				知识库问题
			</div>
			<!-- 请输入知识库相关问题 -->
			<div class="searchCondition">
				<div class="condition">
					<el-checkbox v-model="netSearchEnabled" />&emsp;
					<el-icon>
						<Search />
					</el-icon>
					启用联网搜索
				</div>
				<div class="condition">
					<el-checkbox v-model="mrakdownSearchEnabled" />&emsp;
					<img src="@/assets/images/rebot.png" alt="">
					启用多跳模型推理
				</div>
			</div>
			<div class="inputBigBox">
				<div class="inputArea">
					请输入数据库相关问题
				</div>
				<el-input class="inputTextarea" v-model="inputTextarea" :autosize="{ minRows: 5, maxRows: 10 }"
					type="textarea" placeholder="在此输入您的问题" />
				<div class="inputBtn">
					<!-- 提交问题 -->
					<div class="btn active" @click="submitQuestionBtn">提交问题</div>
					<div class="btn" @click="clearInput">清空</div>
				</div>
			</div>
			<!-- 示例 -->
			<div class="exampleBigBox">
				<div class="problem">
					<div class="title">快速提问示例：</div>
					<div class="listBox">
						<div class="ProblemList content" @click="fileToBox(item, 'problem')" v-for="item in exampleList"
							:key="item.problem">{{
								item.problem }}</div>
					</div>
				</div>
				<div class="file">
					<div class="title">知识库示例：</div>
					<div class="listBox">
						<div class="fileList content" v-for="item in exampleList" :key="item.problem">
							<el-checkbox v-model="item.active" label="" @change="f + fileToBox(item, 'file')" />
							<span>{{ item.name }} &emsp;</span>
							<a :href="item.url" :download="item.name">
								<el-icon>
									<Download />
								</el-icon>
							</a>
						</div>
					</div>
				</div>
			</div>

			<!-- 结果展示区 -->
			<div class="resultArea">
				<div class="navList">
					<div v-for="item in navList" :key="item.title"
						:class="navActive == item.title ? 'NavTitle active' : 'NavTitle'"
						@click="navActive = item.title">{{ item.title }}</div>
				</div>
				<div class="resultContent">
					<div v-if="navActive == '实时检索进展'" v-html="search_display"
						:class="search_display.length > 10 ? 'result' : ''"></div>
					<div v-else v-html="answer" :class="answer.length > 10 ? 'result' : ''"></div>
					<el-icon v-if="isLoading" class="is-loading">
						<Loading />
					</el-icon>
				</div>
			</div>
		</div>
	</div>
	<Footer></Footer>
</template>

<script setup>
import { ref, watch, onMounted } from "vue";
import MarkdownIt from "markdown-it";

// 导入组件
import Header from "@/components/headerView.vue";
import Footer from "@/components/footerView.vue";
// 导入icon
import { Loading, Comment, FolderAdd, Download, Search } from '@element-plus/icons-vue'
// 导入接口api
import { uploadFiles, submitQuestion } from "@/api/reasonrag";
import { reasonragIp } from '@/utils/zongID';
// export let baseURL = 'http://101.43.135.99:3816'
let BASE_URL = reasonragIp
const md = ref(new MarkdownIt());
// 重载选择框用的，处理重复选择相同文件无法二次选择的问题
const fileInputShow = ref(true);
// 输入框内容
const inputTextarea = ref("");
// 文件二进制文件
const netSearchEnabled = ref(true); // 启用联网搜索
const mrakdownSearchEnabled = ref(true); // 启用多跳模型推理
const files = ref([]);
const fileStatus = ref('等待文件上传');// 文件状态
const navList = ref([
	{
		title: "专业回答",
	},
	{
		title: "实时检索进展",
	},
])
const navActive = ref("专业回答");
const uuid = ref("");// 选中的文件的uuid
// 示例文件
const shiliFile = ref(null);
// 示例问题列表
const exampleList = ref(
	[

	]
)

// 接收的答案
const answer = ref("等待提交问题");
// 接收到的实时查询数据
const search_display = ref("等待提交问题");
// 是否在等待回答
const isLoading = ref(false);
// 拖拽读取文件
const handleDrop = (event) => {
	// 阻止默认行为，防止浏览器打开文件
	event.preventDefault();
	const droppedFiles = event.dataTransfer.files; // 获取拖拽的文件
	// 允许的文件类型
	const allowedTypes = ['txt', 'pdf'];
	// 检测文件尾缀
	const validFiles = Array.from(droppedFiles).filter(file => {
		// 获取文件扩展名，转换为小写
		const fileExtension = file.name.split('.').pop().toLowerCase();
		return allowedTypes.includes(fileExtension);
	});
	if (validFiles.length > 0) {
		files.value = [...files.value, ...validFiles];
	} else {
		fileStatus.value = '请选择有效的文件格式';
		// element提示组件
		ElMessage('请选择有效的文件格式');

	}
}
// 点击上传文件
const handleFileChange = (event) => {
	const selectedFiles = event.target.files;
	// 允许的文件类型
	const allowedTypes = ['txt', 'pdf'];
	// 检测文件尾缀
	const validFiles = Array.from(selectedFiles).filter(file => {
		// 获取文件扩展名，转换为小写
		const fileExtension = file.name.split('.').pop().toLowerCase();
		return allowedTypes.includes(fileExtension);
	});

	if (validFiles.length > 0) {
		files.value = [...files.value, ...validFiles];
	} else {
		fileStatus.value = '请选择有效的文件格式';
		ElMessage('请选择有效的文件格式');
	}
}
// 删除文件
const deleteFile = (file) => {
	// 查找并取消实例文件的勾选状态
	const exampleFileIndex = exampleList.value.findIndex(item => item.data === file);
	if (exampleFileIndex > -1) {
		exampleList.value[exampleFileIndex].active = false;
	}
	// 删除文件
	const fileIndex = files.value.indexOf(file);
	if (fileIndex > -1) {
		files.value.splice(fileIndex, 1);
	}
	// 更新文件状态
	fileStatus.value = files.value.length === 0
		? '等待文件上传'
		: `${files.value.length} 个文件已准备好上传`;
	uuid.value = "";
	// 文件选择输入框的内容也需要清空
	fileInputShow.value = false;
	setTimeout(() => {
		fileInputShow.value = true;
	}, 0)
};
// 文件上传操作
const handleUpload = () => {
	// 文件最多不超过五个
	if (files.value.length > 1) {
		fileStatus.value = '已超过文件最大上传数量（1个）';
		ElMessageBox.alert("文件数量不能超过1个", "提示", {
			confirmButtonText: "确定",
			type: "warning",
		}).then(() => {
			return;
		}).catch(() => {
			return
		})
		return;
	}
	// 文件大小不能超过5M
	let totalSize = 0;
	files.value.forEach(file => {
		totalSize += file.size;
	});
	if (totalSize > 5 * 1024 * 1024) {
		fileStatus.value = '已超过文件最大上传大小（5M）';
		ElMessageBox.alert("文件总大小不能超过5M", "提示", {
			confirmButtonText: "确定",
			type: "warning",
		}).then(() => {
			return;
		}).catch(() => {
			return
		})
		return;
	}
	fileStatus.value = '文件上传中...';
	let formData = new FormData();
	files.value.forEach(file => {
		formData.append('files', file);
	});
	// 调用接口上传文件
	uploadFiles(formData).then(res => {
		if (res.id) {
			console.log(res);
			uuid.value = res.id;
			fileStatus.value = res.message;
			ElMessage.success('文件上传成功');
		} else {
			fileStatus.value = res.message;
		}
	}).catch(err => {
		fileStatus.value = '文件上传失败';
		ElMessage.error('文件上传失败');
	});
};
// 文件大小显示处理
const formatFileSize = (size) => {
	if (size < 1024) {
		return size + 'B';
	} else if (size < 1024 * 1024) {
		return (size / 1024).toFixed(2) + 'KB';
	} else if (size < 1024 * 1024 * 1024) {
		return (size / (1024 * 1024)).toFixed(2) + 'MB';
	} else {
		return (size / (1024 * 1024 * 1024)).toFixed(2) + 'GB';
	}
}
// 提交问题
const submitQuestionBtn = async () => {
	// 验证问题
	if (inputTextarea.value === "") {
		ElMessage.warning('请输入知识库相关问题');
		return;
	}
	// 验证文件是否已上传
	if (files.value.length === 0 || uuid.value === "") {
		ElMessage.warning('请先上传文件或选择知识库示例');
		return;
	}
	// 如果在回答则不允许再提交
	if (answer.value === "正在生成回答..." || search_display.value === "正在检索相关信息...") {
		ElMessage.warning('正在生成回答，请稍后');
		return;
	}
	// 初始化状态
	answer.value = "正在生成回答...";
	search_display.value = "正在检索相关信息...";
	isLoading.value = true;
	navActive.value = "专业回答"; // 默认显示专业回答标签页

	const formData = new FormData();
	formData.append('question', inputTextarea.value);
	formData.append('use_search', netSearchEnabled.value);
	formData.append('use_table_format', mrakdownSearchEnabled.value);
	formData.append('id', uuid.value);
	formData.append('multi_hop', false);
	try {
		const response = await fetch(`${BASE_URL}/api/rag-chat`, {
			method: 'POST',
			body: formData
		});

		if (!response.ok || !response.body) {
			throw new Error('请求失败');
		}

		const reader = response.body.getReader();
		const decoder = new TextDecoder('utf-8');
		let buffer = '';

		while (true) {
			const { done, value } = await reader.read();
			if (done) break;

			buffer += decoder.decode(value, { stream: true });

			// 处理可能的多行数据
			const lines = buffer.split('\n');
			buffer = lines.pop() || ''; // 保留未完成的行

			for (const line of lines) {
				if (line.trim() === '') continue;

				if (line.startsWith('data: ')) {
					try {
						const jsonData = JSON.parse(line.substring(6));

						// 更新搜索结果
						if (jsonData.search_display) {
							search_display.value = md.value.render(jsonData.search_display);

						}
						// 更新回答内容
						if (jsonData.answer) {
							answer.value = md.value.render(jsonData.answer);
						}

						// 处理状态信息
						if (jsonData.status) {
							console.log('当前状态:', jsonData.status);
						}
					} catch (e) {
						console.error('解析JSON失败:', e);
					}
				}
			}
		}
	} catch (error) {
		console.error('请求出错:', error);
		answer.value = "请求失败，请重试";
		ElMessage.error('请求失败: ' + error.message);
	} finally {
		isLoading.value = false;
	}
}
// 清空输入框内容
const clearInput = () => {
	inputTextarea.value = "";
}

/** 示例文件选中 */
const fileToBox = (item, type) => {
	if (type === "problem") {
		console.log(item.problem);
		inputTextarea.value = item.problem;
		if (files.value.length === 0) {
			files.value.push(item.data);
			item.active = true;
		}
	}
	if (type === "file") {
		if (item.active) {
			files.value.push(item.data);
			console.table(files.value);
		} else {
			const index = files.value.indexOf(item.data);
			if (index > -1) {
				files.value.splice(index, 1);
			}
			if (files.value.length === 0) {
				uuid.value = "";
				fileStatus.value = '当前未选择文件';
			} else {
				fileStatus.value = `${files.value.length} 个文件已准备好上传`;
			}
		}
	}
}
/** 监听文件列表变化 */
watch(files, (newFiles) => {
	if (newFiles.length === 0) {
		fileStatus.value = '等待文件上传';
	} else if (newFiles.length > 0) {
		handleUpload();
	}
}, { deep: true });
// 在组件挂载时加载示例文件
onMounted(async () => {
	try {
		// 1. 获取CSV文件的URL（假设文件放在public目录下）
		const csvUrl = '/临床诊疗指南.pdf'; // 替换为你的文件路径

		// 2. 获取文件内容
		const response = await fetch(csvUrl);
		const blob = await response.blob();

		// 3. 创建File对象
		shiliFile.value = new File([blob], '临床诊疗指南.pdf', { type: 'application/pdf' });

		// 初始化示例列表
		exampleList.value = [
			{
				problem: "高血压怎么判断？",
				name: "《临床诊疗指南》.pdf",
				url: URL.createObjectURL(shiliFile.value),
				data: shiliFile.value,
				active: false
			}
		];

	} catch (error) {
		console.error('加载示例文件失败:', error);
		// 即使加载失败也初始化示例列表（不带文件）
		exampleList.value = [
			{
				problem: "高血压怎么判断？",
				name: "《临床诊疗指南》.pdf",
				url: '#',
				data: null,
				active: false
			}
		];
	}
});
</script>
<style lang="scss" scoped>
.homeContent {
	display: flex;
	align-items: center;
	justify-content: center;
	height: calc(100vh - 190px);
	box-sizing: border-box;
	max-width: 1750px;
	margin: 50px auto 0 auto;
	min-height: 690px;

	.uploadModule {
		width: 30%;
		height: 100%;
		background-color: #fff;
		border-radius: 2px;
		padding: 10px 20px;
		box-sizing: border-box;

		.iconAndText {
			font-size: 21px;
			color: rgb(11, 57, 81);
			font-weight: 700;
			margin-top: 5px;
			display: flex;
			align-items: center;

			.el-icon {
				font-size: 30px;
				margin-right: 10px;
			}
		}

		// 请先登录或使用示例网站
		.uploadArea {
			width: 100%;
			background-color: rgb(250, 250, 250);
			// 虚线框
			border: 2px dashed #ccc;
			border-radius: 10px;
			margin-top: 20px;
			font-size: 18px;
			color: rgb(11, 57, 81);
			font-weight: 700;
			position: relative;
			cursor: pointer;

			.uploadAreaText {
				height: 280px;
				display: flex;
				align-items: center;
				flex-direction: column;
				justify-content: center;

				.uploadIcont {
					width: 40px;
				}
			}

			.uploadFileList {
				display: flex;
				flex-direction: column;
				width: 100%;
				// margin-top: 10px;
				box-sizing: border-box;
				border-radius: 10px;
				padding: 10px 25px;
				// border: 2px dashed rgb(17, 72, 106);

				.fileItem {
					display: flex;
					align-items: center;
					justify-content: space-between;
					width: 100%;
					margin-top: 5px;

					.fileName {
						height: 25px;
						// 超出隐藏
						overflow: hidden;
						text-overflow: ellipsis;
						white-space: nowrap;
						flex: 1;
						font-size: 17px;
						color: rgb(11, 57, 81);
						font-weight: 700;
					}

					.fileSize {
						margin-left: 10px;
						min-width: 25px;
						font-size: 15px;
						color: #666;
					}

					.deleteIcon {
						min-width: 15px;
						margin-left: 10px;
						position: relative;
						z-index: 1;
						cursor: pointer;
					}
				}
			}

			.fileInput {
				width: 100%;
				height: 100%;
				opacity: 0;
				position: absolute;
				left: 0;
				top: 0;
				cursor: pointer;
			}
		}


		.uploadBtn {
			width: 100%;
			height: 40px;
			background-color: rgb(3, 58, 88);
			border-radius: 10px;
			color: #fff;
			margin-top: 20px;
			display: flex;
			justify-content: center;
			align-items: center;
			cursor: pointer;
		}


		.fileStatus {
			margin-top: 30px;
			// height: calc(100% - 450px);
			height: 230px;
			box-shadow: 2px 2px 12px #aaa;
			border-radius: 5px;

			.text {
				border-radius: 5px 5px 0 0;
				height: 42px;
				font-size: 17px;
				background-color: rgb(240, 241, 243);
				display: flex;
				justify-content: center;
				align-items: center;
			}

			.status {
				border-radius: 0 0 5px 5px;
				height: calc(100% - 42px);
				display: flex;
				justify-content: center;
				align-items: center;
				font-size: 17px;
				color: rgb(11, 57, 81);
				color: #aaa;
			}
		}
	}

	.parseModule {
		padding: 10px 20px;

		box-sizing: border-box;
		width: 50%;
		height: 100%;
		background-color: #fff;
		border-radius: 2px;
		display: flex;
		flex-direction: column;

		.iconAndText {
			font-size: 21px;
			color: rgb(11, 57, 81);
			font-weight: 700;
			margin-top: 5px;
			display: flex;
			align-items: center;

			.el-icon {
				font-size: 30px;
				margin-top: 3px;
				margin-right: 5px;
			}
		}

		.checkboxArea {
			display: flex;
			font-size: 18px;

			.checkboxGroup {
				display: flex;
				align-items: center;
				margin-left: 20px;


			}
		}

		.searchCondition {
			margin-top: 10px;
			display: flex;
			justify-content: space-between;
			align-items: center;
			flex-wrap: wrap;

			.condition {
				.el-checkbox {
					margin-left: 10px;
				}

				width: calc(50% - 20px);
				min-width: 300px;
				padding-left: 20px;
				display: flex;
				align-items: center;

				img {
					width: 20px;
					height: 20px;
				}
			}
		}

		.inputBigBox {
			margin-top: 15px;

			.inputArea {
				font-size: 16px;
				color: rgb(24, 52, 66);
				font-weight: 700;
			}

			.inputTextarea {
				border: 2px solid rgb(4, 57, 89);
				border-radius: 5px;
				margin-top: 10px;
			}

			.inputBtn {
				display: flex;
				margin-top: 15px;

				.btn {
					cursor: pointer;
					width: calc(50% - 10px);
					height: 40px;
					border: 2px solid rgb(4, 57, 89);
					border-radius: 10px;
					color: rgb(17, 72, 106);
					display: flex;
					align-items: center;
					justify-content: center;
					font-size: 17px;
					font-weight: 700;
				}

				.active {
					background-color: rgb(4, 57, 89);
					color: #fff;
					margin-right: 20px;
				}
			}
		}

		.exampleBigBox {
			margin-top: 20px;
			display: flex;
			justify-content: space-around;
			width: 100%;

			.title {
				font-size: 18px;
				color: rgb(11, 57, 81);
				font-weight: 700;
				margin-top: 20px;
			}

			.problem {
				width: calc(50% - 10px);

			}

			.file {
				width: calc(50% - 10px);
				margin-left: 20px;
			}

			.listBox {
				// margin-top: 15px;
				width: 100%;
				max-height: 350px;
				overflow-y: auto;

				.content {
					height: 20px;
					line-height: 20px;
					margin: 12px 0;
				}

				;

				.ProblemList {
					text-align: center;
					font-weight: 400;
					font-size: 14px;
					border: 1px solid rgb(11, 57, 81);
					padding: 5px 10px;
					border-radius: 10px;

				}

				.fileList {
					display: flex;
					align-items: center;
					padding: 6px 10px;

					a {
						margin-bottom: -3px;
					}
				}
			}

		}

		.resultArea {
			flex: 1;
			margin: 10px 0;
			height: 200px;
			box-shadow: 2px 2px 12px #aaa;
			border-radius: 5px;

			.navList {
				border-radius: 5px 5px 0 0;
				// height: 42px;
				font-size: 17px;
				background-color: rgb(240, 241, 243);
				display: flex;
				align-items: center;
				justify-content: center;

				.NavTitle {
					padding: 13px;
					color: #666;
					font-weight: 700;
				}

				.active {
					color: rgb(17, 72, 106);
					// border-bottom: 3px solid rgb(24, 52, 66);
				}
			}
			.resultContent {
				border-radius: 0 0 5px 5px;
				height: calc(100% - 79px);
				display: flex;
				// justify-content: center;
				flex-direction: column;
				// align-items: center;
				padding: 15px 30px;
				overflow-x: auto;
				font-size: 17px;
				color: rgb(11, 57, 81);
				color: #aaa;

				.result {
					color: #000;
				}
			}
		}
	}
}

// md表单样式单独修改

:deep(table) {
	width: 100%;
	border-collapse: collapse;
	margin: 1rem 0;
}

:deep(table th),
:deep(td) {
	border: 1px solid #ddd;
	padding: 8px;
	text-align: left;
}

:deep(table th) {
	background-color: #f5f7fa;
	font-weight: bold;
}

:deep(table tr:nth-child(even) td) {
	background-color: #fbfcfd;
}

:deep(ul) {
	list-style: none;
}

:deep(ol) {
	list-style: none;
}
</style>
